﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Fakes;
using Microsoft.Practices.Unity;
using Microsoft.QualityTools.Testing.Fakes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sern.Abstracts.Tracker.DataContracts;
using Sern.Common;
using Sern.ServiceImplementation;
using Sern.ServiceImplementation.Fakes;
using Sern.ServiceImplementation.TrackerDefinition.Data;
using Sern.ServiceImplementation.TrackerDefinition.Service;

namespace Sern.Test.ServiceImplementation.TrackerDefinition.Service
{
    [TestClass]
// ReSharper disable InconsistentNaming
    public class TrackerHost_InitializationAndAutomaticListener
// ReSharper restore InconsistentNaming
    {
        [TestInitialize]
        public void Init()
        {
            ComponentLocator.Reset();

            new Sern.ServiceImplementation.LocalRegistrar().Register(ComponentLocator.Unity);

            ComponentLocator.Unity.RegisterTestInstance("SampleHostName","HostName");
            ComponentLocator.Unity.RegisterTestInstance<IEnumerable<string>>(new string[]{"Test","Hosting New Tracker"},"Keywords");
            ComponentLocator.Unity.RegisterTestInstance<string>("First tracker hosting test", "Description");

            ComponentLocator.Unity.RegisterInstance(
                RepositoryFactory.CreateStub<Client>());

            ComponentLocator.Unity.RegisterInstance(
                RepositoryFactory.CreateStub<ClientStatusInfo>());

            ComponentLocator.Unity.RegisterInstance(
                RepositoryFactory.CreateStub<JobDescription>());

            ComponentLocator.Unity.RegisterInstance(
                RepositoryFactory.CreateStub<JobKeyword>());            

            ComponentLocator.Unity.RegisterInstance<IListenerFactory>(
                new StubIListenerFactory
                    {
                        CreateUriUriClientTypeObject = (baseUri, operationUri, clientType, instance)
                                                       =>
                            {
                                ComponentLocator.Unity.ResolveTest<Action<Uri, Uri, ClientType, object>>(
                                    "CreateUriCalledEventHandler")
                                    (baseUri, operationUri, clientType, instance);

                                return new Listener
                                    {
                                        Open = () =>
                                               ComponentLocator.Unity.ResolveTest<Action<Uri, Uri, ClientType, object>>(
                                                   "OpenListenerCalledEventHandler")(baseUri, operationUri, clientType,
                                                                                     instance),

                                        Close = () =>
                                                ComponentLocator.Unity.ResolveTest<Action<Uri, Uri, ClientType, object>>(
                                                    "CloseListenerCalledEventHandler")(baseUri, operationUri, clientType,
                                                                                       instance),

                                        Dispose = () => { }
                                    };
                            }
                    }
                );
        }

        [TestMethod]
        public void Test()
        {
            var trackerHost = new TrackerHost(ComponentLocator.Unity.ResolveTest<string>("HostName"));

            List<ClientListenerModel> createdListeners = new List<ClientListenerModel>();

            ComponentLocator.Unity.RegisterTestInstance < Action<Uri, Uri, ClientType, object>>(
                (baseUri, operationUri, clientType, instance) => createdListeners.Add
                    (new ClientListenerModel
                        {
                            BaseUri = baseUri.AbsoluteUri,
                            OperationUri = operationUri.OriginalString,
                            ClientType = clientType,
                            ListenerState = ListenerState.Initialized,
                            SingletonInstance = instance
                        }), "CreateUriCalledEventHandler");

            ComponentLocator.Unity.RegisterTestInstance<Action<Uri, Uri, ClientType, object>>(
                (baseUri, operationUri, clientType, instance) => createdListeners.Add
                    (new ClientListenerModel
                    {
                        BaseUri = baseUri.AbsoluteUri,
                        OperationUri = operationUri.OriginalString,
                        ClientType = clientType,
                        ListenerState = ListenerState.Opened,
                        SingletonInstance = instance
                    }), "OpenListenerCalledEventHandler");

            ComponentLocator.Unity.RegisterTestInstance<Action<Uri, Uri, ClientType, object>>(
                (baseUri, operationUri, clientType, instance) => createdListeners.Add
                    (new ClientListenerModel
                    {
                        BaseUri = baseUri.AbsoluteUri,
                        OperationUri = operationUri.OriginalString,
                        ClientType = clientType,
                        ListenerState = ListenerState.Closed,
                        SingletonInstance = instance
                    }), "CloseListenerCalledEventHandler");

            trackerHost.Initialize();

            Assert.IsTrue(createdListeners.Any(l => l.ClientType == ClientType.TrackerHost && l.ListenerState == ListenerState.Initialized));
            Assert.IsTrue(createdListeners.Any(l => l.ClientType == ClientType.TrackerHost && l.ListenerState == ListenerState.Opened));
            //Check that the new tracker exists in the fake persistence
            //Check that listeners are fired in a way that makes sense.
            //Check that keywords are correct. (This could be delegated to another class!

            //trackerHost.StartANewJob(
            //    ComponentLocator.Unity.ResolveTest<IEnumerable<string>>("Keywords"),
            //    ComponentLocator.Unity.ResolveTest<string>("Description"));
        }
    }
}
